package net.yondervision.hrfsp.sdk.esign.core;

import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.APPLICATION_JSON;
import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.HEADER_APP_ID;
import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.HEADER_TOKEN;
import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.URL_PARAM_PATH_PREFIX;
import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.URL_PARAM_PATH_SUFFIX;
import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.URL_PARAM_SEPARATOR;
import static net.yondervision.hrfsp.sdk.esign.domain.ESignConstant.URL_SEPARATOR;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.base.Stopwatch;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import lombok.extern.slf4j.Slf4j;
import net.yondervision.hrfsp.sdk.esign.core.util.DefaultResultJsonResolver;
import net.yondervision.hrfsp.sdk.esign.domain.AbstractESignResponse;
import net.yondervision.hrfsp.sdk.esign.domain.ESignRequest;
import net.yondervision.hrfsp.sdk.esign.domain.ParamBody;
import net.yondervision.hrfsp.sdk.esign.domain.ParamPath;
import net.yondervision.hrfsp.sdk.esign.domain.ParamQuery;

/**
 * @author Cash Zhang
 * @version v1.0
 * @since 2019/09/26 21:30
 */
@Slf4j
public class DefaultESignClient implements ESignClient {

  @Override
  public <T extends AbstractESignResponse> T execute(ESignRequest<T> request) {
    Stopwatch stopwatch = Stopwatch.createStarted();
    ParamPath paramPath = request.getParamPath();
    ParamQuery paramQuery = request.getParamQuery();
    ParamBody paramBody = request.getParamBody();
    String jsonParamBod = null;
    String newUrl = request.getUrl();
    if (Objects.nonNull(paramPath)) {
      Map<String, Object> paramMap = BeanUtil.beanToMap(paramPath);
      for (Entry<String, Object> entry : paramMap.entrySet()) {
        newUrl = newUrl.replace(URL_PARAM_PATH_PREFIX + entry.getKey() + URL_PARAM_PATH_SUFFIX,
            String.valueOf(Optional.ofNullable(entry.getValue()).orElseGet(String::new)));
      }
    }
    if (Objects.nonNull(paramQuery)) {
      Map<String, Object> paramMap = BeanUtil.beanToMap(paramQuery);
      String params = HttpUtil.toParams(paramMap);
      newUrl = newUrl + URL_PARAM_SEPARATOR + params;
    }
    if (Objects.nonNull(paramBody)) {
      jsonParamBod = JSONUtil.toJsonStr(paramBody);
    }
    String resultUrl =
        request.getServerHost() + URL_SEPARATOR + request.getVersion() + newUrl;
    String resultJson = HttpUtil.createRequest(request.getMethodType(),resultUrl)
        .header(HEADER_APP_ID, request.getAppId())
        .header(HEADER_TOKEN, request.getAccessToken())
        .contentType(APPLICATION_JSON)
        .body(jsonParamBod)
        .execute()
        .body();
    log.info("esign,request url is :{}, return json is : {}", resultUrl, resultJson);
    T result = DefaultResultJsonResolver.resolve(request, resultJson);
    log.info("the method executed successfully, taking [{}] .",
        stopwatch.stop().toString());
    return result;
  }

}
